package org.rm.controladores;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rm.entidades.ExParcial;
import org.rm.entidades.Exp;
import org.rm.entidades.ExperienciaBase;
import org.rm.entidades.Jugadores;
import org.rm.entidades.Partida;
import org.rm.entidades.jpa.ExParcialController;
import org.rm.entidades.jpa.JpaExperiencia;
import org.rm.entidades.jpa.JugadoresJpaController;
import org.rm.entidades.jpa.PartidaJpaController;
import org.rm.entidades.jpa.exceptions.NonexistentEntityException;

/**
 * Clase para gestionar las experiencias
 * 
 * @author ffbeltran
 */
public class ControladorExperiencia {

	/**
	 * Método que añade una nueva experiencia. 
	 * @param exp experiencia a añadir
	 * @param jugadores que participan en la partida
	 * @return devuelve la experiencia base añadida
	 */
	public ExperienciaBase nuevaExperiencia(ExperienciaBase exp, Collection<Jugadores> jugadores) {
		exp.setId(null);
		exp.actualizaExp();
		JpaExperiencia.create(exp);
		calculaExperiencia(exp, jugadores);
		return exp;
	}

	/**
	 * Método que modifica una experiencia
	 * @param exp experiencia que ha sido modificada
	 * @param jugadores que participan en la partida
	 */
	public void modificaExperiencia(ExperienciaBase exp, Collection<Jugadores> jugadores) {
		ExperienciaBase antiguo;
		try {
			antiguo = JpaExperiencia.findExperienciaBase(exp.getClass(), exp.getId());
			if (antiguo.getExp() == null)
				antiguo.actualizaExp();
			antiguo.setExp(antiguo.getExp() * -1);
			exp.actualizaExp();
			JpaExperiencia.edit(exp);
			List<ExperienciaBase> expList = new ArrayList<ExperienciaBase>();
			expList.add(antiguo);
			expList.add(exp);
			calculaExperiencia(expList, jugadores);
		} catch (NonexistentEntityException ex) {
			ex.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * Elimina una experiencia determinada
	 * @param exp experiencia a eliminar
	 * @param jugadores que participan en la partida
	 */
	public void eliminaExperiencia(ExperienciaBase exp, Collection<Jugadores> jugadores) {
		if (exp != null) {
			exp.actualizaExp();
			exp.setExp(exp.getExp() * -1);
		}
		try {
			JpaExperiencia.destroy(exp.getClass(), exp.getId());
			calculaExperiencia(exp, jugadores);
		} catch (NonexistentEntityException ex) {
			ex.printStackTrace();
		}
	}
	
	public List<ExperienciaBase> consultaExperiencias(Class<ExperienciaBase> clazz, Integer idPartida) {
		return JpaExperiencia.findExperienciaBaseEntities(clazz, idPartida);
	}

	private void calculaExperiencia(Exp experiencia,
			Collection<Jugadores> jugadores) {
		List<Exp> expList = new ArrayList<Exp>();
		expList.add(experiencia);
		calculaExperiencia(expList, jugadores);
	}

	private void calculaExperiencia(List<? extends Exp> experiencia,
			Collection<Jugadores> jugadores) {
		Map<Partida, Integer> expCompartida = new HashMap<Partida, Integer>();

		for (Partida aux : PartidaJpaController.findPartidaEntities()) {
			expCompartida.put(aux, 0);
		}

		for (Jugadores jugadorActual : jugadores) {
			for (Exp exp : experiencia) {
				if (exp.getJugador().equals(jugadorActual)) {
					int expSign = (exp.getExp() >= 0) ? 1 : -1;
					int expAbs = Math.abs(exp.getExp());
					int expComp = (int) Math.ceil(((double) expAbs
							* exp.getCompartido() / 100));
					int expJugador = (expAbs - expComp) * expSign;
					expComp = (int) Math.ceil((double) expComp
							/ jugadores.size());
					Partida p = PartidaJpaController.findPartida(exp
							.getIdPartida());
					addExpJugador(jugadorActual, expJugador, p);
					Integer aux = expCompartida.get(p);
					expCompartida.put(p, aux + (expComp * expSign));
				}
			}
		}

		for (Partida p : expCompartida.keySet()) {
			int expCompartidaGeneral = expCompartida.get(p);
			for (Jugadores jugadorActual : jugadores) {
				addExpJugador(jugadorActual, expCompartidaGeneral, p);
			}
		}
	}

	private void addExpJugador(Jugadores jugador, int exp, Partida partida) {
		boolean exist = false;
		ExParcial exParcial;

		for (ExParcial aux : jugador.getExperiencia()) {
			if (aux.getPartida().equals(partida)) {
				exParcial = aux;
				exParcial.setExperiencia(exParcial.getExperiencia() + exp);
				exist = true;
				break;
			}
		}
		if (!exist) {
			exParcial = new ExParcial(exp, partida);
			ExParcialController.create(exParcial);
			jugador.getExperiencia().add(exParcial);
		}
		try {
			JugadoresJpaController.edit(jugador);
		} catch (NonexistentEntityException e) {
			e.printStackTrace();
		}
	}

}
